#include "Worker.hpp"

#include <QDebug>
Worker::Worker(QObject *parent)
    : QThread(parent)
{}

void Worker::run()
{
    //    qDebug() << Q_FUNC_INFO;

    rysuj();
}

void Worker::setRozmiar(double rozm){
    //    qDebug() << Q_FUNC_INFO << rozm;
    rozmiar_a = rozm;
}

void Worker::setSigma(double sigma){
    //    qDebug() << Q_FUNC_INFO << sigma;
    this->sigma = sigma;
}

void Worker::setPartitions(int n){
    //    qDebug() << Q_FUNC_INFO << n;
    n_podzialow = n;
}

void Worker::setInput(Input inp){
    m_input = inp;
}
void Worker::setVB(bool a){
    valence_band = a;
}

void Worker::oblicz_ww(){
//    QVector<double> potencjal, v_tylda, vec_x,vec_y,temp_vec_x,temp_vec_y;
//    double z_min, z_max, temp1_ww;//, temp2_ww;
//    int liczba_ww;//, first_ww;

//    double skok_s,skala_alpha;
//    double /*bez_wym_a,bez_wym_b,*/v_c;

//    //bez_wym_a = -1.0;
//    //bez_wym_b = 1.0;
//    skok_s = 2.0/n_podzialow;

//    Result result;

//    for ( int pot_i = 0; pot_i < m_input.records.size() ;++pot_i){
//        potencjal = m_input.records.at(pot_i).vec_y;

//        v_c = maksimum(potencjal);
//        skala_alpha = 2*rozmiar_a*rozmiar_a*v_c;
//        v_tylda = zbewymiaruj(potencjal,skok_s,skala_alpha);
//        z_min = minimum(v_tylda);
//        z_max = maksimum(v_tylda);

//        liczba_ww = lww(z_max,v_tylda,-1.0);

//        for (int i = 0 ; i < potencjal.size(); i++){
//            vec_x.push_back(-rozmiar_a/2 + i*rozmiar_a/n_podzialow);
//            vec_y.push_back(potencjal.at(i)*v_c );
//        }

//        //        result.addData(vec_x, vec_y);
//        vec_y.clear();
//        vec_x.clear();

//        for ( int j = 1; j <= liczba_ww;j++){
//            temp1_ww = wartosc_wlasna(v_tylda,-1.0,j,z_min,z_max,sigma);
//            //            qDebug() << temp1_ww/(skala_alpha*pow(skok_s,2));
//            temp_vec_y.push_back(temp1_ww*v_c/(skala_alpha*pow(skok_s,2)));
//            temp_vec_x.push_back(-rozmiar_a/2.0);
//            temp_vec_y.push_back(temp1_ww*v_c/(skala_alpha*pow(skok_s,2)));
//            temp_vec_x.push_back(rozmiar_a/2.0);
//            result.addData(temp_vec_x,temp_vec_y);

//            temp_vec_y.clear();
//            temp_vec_x.clear();

//            emit notifyProgress(100*j/liczba_ww);
//        }
//    }
//    emit ready(result);
}

void Worker::rysuj(){
qDebug() << Q_FUNC_INFO;
    double n = n_podzialow;
    QVector <double> v;
    QVector <double> meff;
    Result result;


    v = m_input.vec_v;
    meff = m_input.vec_mass;

    double L = rozmiar_a; // [nm]
    //    double zakres1 = -L/2;
    //    double zakres2 = L/2;
    double s = L / n ;
    double h = 6.67; // E-34
    double pi = 3.14159;
    double me = 9.109383; //E-31
    double q = 1.6; //E-19
    double alfa;

    alfa = - 8 * me * pi * pi * q / ( h * h );
    //qDebug() << "alfa" << alfa;
//     if (valence_band)
//         alfa = -alfa;

    double vmax = -1e30, vmin = 1e30;
    for (int i = 0; i < v.size(); ++i){
        v[i] = v.at(i) * alfa * s * s;
        if (v.at(i) > vmax)
            vmax = v.at(i);
        if (v.at(i) < vmin)
            vmin = v.at(i);
    }


    int Enmax;
    double z1 = vmin , z2 = 4 + vmax, z2const = z2;
    double z = (z1+z2)/2;
    double u, u_minus1;
    int count = 0;
    int Enumber = 1;

    for (int i = 0; i < v.size(); ++i){
        if ( i == 0 ){
            u_minus1 = 2.0/meff.at(0) + v.at(0) - vmax;
            u = u_minus1;
        } else{
            u_minus1 = u;
            u = 1.0/meff.at(i) + 1.0/meff.at(i-1) + v.at(i) - vmax - 1.0/(u_minus1 * meff.at(i-1)*meff.at(i-1));
        }
        if ( u < 0 )
            count++;
    }
    Enmax = count;

    while ( Enumber <= Enmax ){
        count = 0;
        for (int i = 0; i < v.size(); ++i){
            if ( i == 0 ){
                u_minus1 = 2.0/meff.at(0) + v.at(0) - z;
                u = u_minus1;
            } else{
                u_minus1 = u;
                u = 1.0/meff.at(i) + 1.0/meff.at(i-1) + v.at(i) - z - 1.0/(u_minus1 * meff.at(i-1)*meff.at(i-1));
            }
            if ( u < 0 )
                count++;
        }
        if (count >= Enumber)
            z2 = z;
        if (count < Enumber)
            z1 = z;

        z = (z1+z2)/2;

        if ( z2 - z1 < sigma ){

//            QVector <double> Ominus(n+1,0.0);
//            QVector <double> Oplus(n+1,0.0);
//            QVector <double> psi(n+1,0.0);

//            double rj, rjmin;
//            int jj = 1;
//            for (int j = 1; j < n; ++j){
//                Ominus[0] = 1/(2.0/meff.at(0) + v.at(0) - z);
//                for (int i = 1; i < j; i++){
//                    Ominus[i] = 1/(1.0/meff.at(i) + 1.0/meff.at(i-1) + v.at(i) - z - Ominus.at(i-1)/(meff.at(i-1)*meff.at(i-1)));
//                }
//                Oplus[n] = 1/(2.0/meff.at(n) + v.at(n)-z);
//                for (int i = n-1; i > j; --i){
//                    Oplus[i] = 1/(1.0/meff.at(i) + 1.0/meff.at(i-1) + v.at(i) - z - Oplus.at(i+1)/(meff.at(i)*meff.at(i)));
//                }
//                rj = abs(-Ominus.at(j-1)/(meff.at(j-1)*meff.at(j-1))+ v.at(j) + 1.0/meff.at(j) + 1.0/meff.at(j-1) - z - Oplus.at(j+1)/(meff.at(j)*meff.at(j)));
//                if (j == 1){
//                    rjmin = rj;
//                }
//                if (rj < rjmin){
//                    rjmin = rj;
//                    jj = j;
//                }
//            }

//            Ominus[0] = 1/(2.0/meff.at(0) + v.at(0) - z);
//            for (int i = 1; i < jj; i++){
//                Ominus[i] = 1/(1.0/meff.at(i) + 1.0/meff.at(i-1) + v.at(i) - z - Ominus.at(i-1)/(meff.at(i-1)*meff.at(i-1)));
//            }
//            Oplus[n] = 1/(2.0/meff.at(n) + v.at(n)-z);
//            for (int i = n-1; i > jj; --i){
//                Oplus[i] = 1/(1.0/meff.at(i) + 1.0/meff.at(i-1) + v.at(i) - z - Oplus.at(i+1)/(meff.at(i)*meff.at(i)));
//            }
//            psi[jj] = 1;
//            for (int i = jj+1; i < psi.size(); ++i){
//                psi[i] = 1/meff.at(i-1)*Oplus.at(i)*psi.at(i-1);
//            }
//            for (int i = jj-1; i >= 0; --i){
//                psi[i] = 1/meff.at(i)*Ominus.at(i)*psi.at(i+1);
//            }
//            double psimax = psi.at(0);
//            for (int i = 1; i < psi.size(); ++i){
//                if (psi[i] > psimax)
//                    psimax = psi.at(i);
//            }
//            for (int i = 0; i < psi.size(); ++i){
//                psi[i] = psi.at(i) / psimax;
//            }

            double energy = z/(alfa * s * s);
            if (valence_band)
                energy *= -1.0;
//            for (int i = 0; i < psi.size(); ++i){
//                psi[i] *= 2.0/L;
//            }
            result.addData(energy,v);
            Enumber++ ;
            z2 = z2const;
            emit notifyProgress(Enumber*100/Enmax);
        }
    }
    qDebug() << Q_FUNC_INFO;
    emit ready(result);
}

QVector<double> Worker::generuj_potencjal(double a, double b, int n){
    QVector<double> vec;
    double s = (b-a)/n;
    for(int i = 0; i <= n; i++){
        if((a+i*s < -0.5 ) || (a+i*s > 0.5 ) )
            vec.push_back( 1.519 );
        else
            vec.push_back(1.002);
    }

    return vec;
}

double Worker::lww(double z, const QVector<double> d, const double e){
    double u;
    int i,n;
    n = 0;
    i = 1;
    u = d.at(0) + 2.0  - z;
    while(i < d.size()){
        if ( u < 0 )
            n++;
        u = d.at(i) + 2.0 - z - pow(e,2)/u;
        i++;
    }
    return n;
}

double Worker::wartosc_wlasna( const QVector<double> d,const double e, int j,double z_min, double z_max, double sigma){
    double z_p;
    while (z_max - z_min > sigma ){
        z_p = (z_min + z_max)/2.0;
        if (lww(z_p,d,e) < j){
            z_min = z_p;
        }else
            z_max = z_p;
    }
    return (z_min + z_max)/2.0;
}

double Worker::minimum(QVector<double> vec){
    if (!vec.empty()){
        double min = vec.at(0);
        for (int i = 0; i < vec.size(); i++){
            if (vec.at(i) < min)
                min = vec.at(i);
        }
        return min;
    } else
        return 0;

}

double Worker::maksimum(QVector<double> vec){
    if (!vec.empty()){
        double max = vec.at(0);
        for (int i = 0; i < vec.size(); i++){
            if (vec.at(i) > max)
                max = vec.at(i);
        }
        return max;
    } else
        return 0;

}

QVector<double> Worker::zbewymiaruj(QVector<double> vec,double s,double alpha){
    if(!vec.empty()){
        for(int i = 0; i < vec.size(); i++){
            vec[i] *= alpha*s*s;
        }
    }
    return vec;
}
